#include "stdafx.h"
#include "WaterView.h"

#include "GlobalAppData.h"
#include "LoadShader.h"
#include "InputLayouts.h"
#include "LoadTexture.h"

#include "Renderer.h"

#include "sparse_matrix.h"
#include "pcg_solver.h"

#include <ctime>

using namespace mfluid;

#define GRID_SIZE_X 128
#define GRID_SIZE_Y 128

#define IDX(x,y) ((y)*GRID_SIZE_X + (x))

static float pressure[GRID_SIZE_X * GRID_SIZE_Y];
static float divergence[GRID_SIZE_X * GRID_SIZE_Y];
static float densityBuffer0[GRID_SIZE_X * GRID_SIZE_Y];
static float densityBuffer1[GRID_SIZE_X * GRID_SIZE_Y];
static float velXSources[GRID_SIZE_X * GRID_SIZE_Y];
static float velYSources[GRID_SIZE_X * GRID_SIZE_Y];
static float densitySources[GRID_SIZE_X * GRID_SIZE_Y];
static float velocityXBuffer0[(GRID_SIZE_X + 1) * (GRID_SIZE_Y)];
static float velocityXBuffer1[(GRID_SIZE_X + 1) * (GRID_SIZE_Y)];
static float velocityYBuffer0[(GRID_SIZE_X) * (GRID_SIZE_Y + 1)];
static float velocityYBuffer1[(GRID_SIZE_X) * (GRID_SIZE_Y + 1)];
static int cellType[GRID_SIZE_X * GRID_SIZE_Y];

static SparseMatrix<float> matrix = SparseMatrix<float>((GRID_SIZE_X-2) * (GRID_SIZE_Y-2),5);

#define FLUID 0
#define SOLID 1
#define AIR   2

static mgfx::TextureID mFluidDensityTex;

static float * density;
static float * densityPrev;
static float * velX;
static float * velY;
static float * velXPrev;
static float * velYPrev;

static mgfx::VertexBufferID mSpriteVertexBuffer;
static mgfx::IndexBufferID mSpriteIndexBuffer;

static mgfx::ShaderID mShaderFluid;
static mgfx::ShaderID mShaderSprite;
static mgfx::TextureID mArrowTex;

static int mPrevMousePosX, mPrevMousePosY;

static bool mDrawVelocity;

static void createSpriteBuffers();

static void advectVelX(float * v1, float * v0, float * velX, float * velY, float dt)
{
	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(int x = 0; x < GRID_SIZE_X + 1; x++)
		{
			if(x == 0)
				if(cellType[IDX(x, y)] == SOLID) continue;
			if(x > 0)
				if(cellType[IDX(x-1, y)] == SOLID || cellType[IDX(x, y)] == SOLID)
					continue;

			float localVelX = velX[IDX(x, y)];
			float localVelY = 0.25f * (velY[IDX(x-1, y)] + velY[IDX(x, y)] + velY[IDX(x-1, y+1)] + velY[IDX(x, y+1)]);

			float xPrev = x - dt * localVelX;
			float yPrev = y - dt * localVelY;

			xPrev = (std::max)(xPrev, 0.0f);
			xPrev = (std::min)(xPrev, GRID_SIZE_X - 0.0001f);

			size_t xP0 = (size_t)xPrev;
			size_t xP1 = xP0 + 1;

			yPrev = (std::max)(yPrev, 0.0f);
			yPrev = (std::min)(yPrev, GRID_SIZE_Y - 1.0001f);

			size_t yP0 = (size_t)yPrev;
			size_t yP1 = yP0 + 1;

			float s0 = xP1 - xPrev;
			float s1 = 1 - s0;
			float t0 = yP1 - yPrev;
			float t1 = 1 - t0;

			v1[IDX(x, y)] = s0 * (t0 * v0[IDX(xP0, yP0)] + t1 * v0[IDX(xP0, yP1)]) +
							s1 * (t0 * v0[IDX(xP1, yP0)] + t1 * v0[IDX(xP1, yP1)]);
		}
	}
}

static void advectVelY(float * v1, float * v0, float * velX, float * velY, float dt)
{
	for(int y = 0; y < GRID_SIZE_Y + 1; y++)
	{
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			if(y == 0)
				if(cellType[IDX(x, y)] == SOLID) continue;
			if(y > 0)
				if(cellType[IDX(x, y-1)] == SOLID || cellType[IDX(x, y)] == SOLID)
					continue;

			float localVelX = 0.25f * (velX[IDX(x, y-1)] + velX[IDX(x+1, y-1)] + velX[IDX(x, y)] + velX[IDX(x+1, y)]);
			float localVelY = velY[IDX(x,y)];

			float xPrev = x - dt * localVelX;
			float yPrev = y - dt * localVelY;

			xPrev = (std::max)(xPrev, 0.0f);
			xPrev = (std::min)(xPrev, GRID_SIZE_X - 1.0001f);

			size_t xP0 = (size_t)xPrev;
			size_t xP1 = xP0 + 1;

			yPrev = (std::max)(yPrev, 0.0f);
			yPrev = (std::min)(yPrev, GRID_SIZE_Y - 0.0001f);

			size_t yP0 = (size_t)yPrev;
			size_t yP1 = yP0 + 1;

			float s0 = xP1 - xPrev;
			float s1 = 1 - s0;
			float t0 = yP1 - yPrev;
			float t1 = 1 - t0;

			v1[IDX(x, y)] = s0 * (t0 * v0[IDX(xP0, yP0)] + t1 * v0[IDX(xP0, yP1)]) +
				s1 * (t0 * v0[IDX(xP1, yP0)] + t1 * v0[IDX(xP1, yP1)]);
		}
	}
}

static void advectCellValue(float * v1, float * v0, float * velX, float * velY, float dt)
{
	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x, y)] != FLUID)
				continue;

			float localVelX = 0.5f * (velX[IDX(x, y)] + velX[IDX(x+1,y)]);
			float localVelY = 0.5f * (velY[IDX(x, y)] + velY[IDX(x,y+1)]);

			float xPrev = x - dt * localVelX;
			float yPrev = y - dt * localVelY;

			xPrev = (std::max)(xPrev, 0.0f);
			xPrev = (std::min)(xPrev, GRID_SIZE_X - 1.0001f);

			size_t xP0 = (size_t)xPrev;
			size_t xP1 = xP0 + 1;

			yPrev = (std::max)(yPrev, 0.0f);
			yPrev = (std::min)(yPrev, GRID_SIZE_Y - 1.0001f);

			size_t yP0 = (size_t)yPrev;
			size_t yP1 = yP0 + 1;

			float s0 = xP1 - xPrev;
			float s1 = 1 - s0;
			float t0 = yP1 - yPrev;
			float t1 = 1 - t0;

			v1[IDX(x, y)] = s0 * (t0 * v0[IDX(xP0, yP0)] + t1 * v0[IDX(xP0, yP1)]) +
				s1 * (t0 * v0[IDX(xP1, yP0)] + t1 * v0[IDX(xP1, yP1)]);
		}
	}
}

#define PIDX(x,y) (((y)-1)*(GRID_SIZE_X-2) + ((x)-1))

static void projectPcg(float * u, float * v, float * p, float * div, float dt)
{
	float hX = 1.0f / GRID_SIZE_X;
	float hY = 1.0f / GRID_SIZE_Y;

	float rho = 1;
	float scale = dt / (rho*hX*hY);

	//matrix.clear();
	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			int mat_index = PIDX(x,y);
			if(cellType[IDX(x,y)] == FLUID)
			{
				divergence[mat_index] =	-((u[IDX(x+1, y)] - u[IDX(x, y)]) / hX +
										  (v[IDX(x, y+1)] - v[IDX(x, y)]) / hY);

				matrix.set_element(mat_index, mat_index, 0);
				if(cellType[IDX(x-1,y)] == FLUID)
				{
					int neigh_mat_index = PIDX(x-1,y);
					matrix.add_to_element(mat_index, mat_index, scale);
					matrix.set_element(mat_index, neigh_mat_index, -scale);
				} else divergence[mat_index] -= u[IDX(x, y)] / hX;
				if(cellType[IDX(x+1,y)] == FLUID)
				{
					int neigh_mat_index = PIDX(x+1,y);
					matrix.add_to_element(mat_index, mat_index, scale);
					matrix.set_element(mat_index, neigh_mat_index, -scale);
				} else divergence[mat_index] += u[IDX(x+1, y)] / hX;
				if(cellType[IDX(x,y-1)] == FLUID)
				{
					int neigh_mat_index = PIDX(x,y-1);
					matrix.add_to_element(mat_index, mat_index, scale);
					matrix.set_element(mat_index, neigh_mat_index, -scale);
				} else divergence[mat_index] -= v[IDX(x, y)] / hY;
				if(cellType[IDX(x,y+1)] == FLUID)
				{
					int neigh_mat_index = PIDX(x,y+1);
					matrix.add_to_element(mat_index, mat_index, scale);
					matrix.set_element(mat_index, neigh_mat_index, -scale);
				} else divergence[mat_index] += v[IDX(x, y+1)] / hY;
			}
		}
	}

	static PCGSolver<float> solver;
	static std::vector<float> rhs = std::vector<float>((GRID_SIZE_X-2)*(GRID_SIZE_Y-2));
	for(int i = 0; i < (GRID_SIZE_X-2)*(GRID_SIZE_Y-2); i++)
		rhs[i] = divergence[i];

	static std::vector<float> result = std::vector<float>((GRID_SIZE_X-2)*(GRID_SIZE_Y-2));
	float residual;
	int iterations;
	bool success = solver.solve(matrix, rhs, result, residual, iterations);

	float scaleX = dt / (rho * hX);
	float scaleY = dt / (rho * hY);
	for(size_t y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] != FLUID) continue;
			u[IDX(x  , y)] -= scaleX * result[PIDX(x, y)];
			u[IDX(x+1, y)] += scaleX * result[PIDX(x, y)];

			v[IDX(x, y  )] -= scaleY * result[PIDX(x, y)];
			v[IDX(x, y+1)] += scaleY * result[PIDX(x, y)];
		}
	}

	float maxDiv = 0, sumDiv = 0;
	int numCells = 0;
	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] == FLUID)
			{
				float cellDiv		 =	-(hX * (u[IDX(x+1, y)] - u[IDX(x, y)]) +
										  hY * (v[IDX(x, y+1)] - v[IDX(x, y)]));
				maxDiv = (std::max)(maxDiv, fabsf(cellDiv));
				sumDiv += fabsf(cellDiv);

				numCells++;
			}
		}
	}
	float avgDiv = sumDiv / numCells;
}

static void project(float * u, float * v, float * p, float * div)
{

	float hX = 1.0f / GRID_SIZE_X;
	float hY = 1.0f / GRID_SIZE_Y;

	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] == FLUID)
			{
				divergence[IDX(x, y)] =	-(hX * (u[IDX(x+1, y)] - u[IDX(x, y)]) +
										  hY * (v[IDX(x, y+1)] - v[IDX(x, y)]));
			}
			p[IDX(x, y)] = 0;
		}
	}

	for(uint k = 0; k < 100; k++)
	{
		for(size_t y = 0; y < GRID_SIZE_Y; y++)
		{
			for(size_t x = 0; x < GRID_SIZE_X; x++)
			{
				if(cellType[IDX(x,y)] != FLUID) continue;
				p[IDX(x, y)] = (divergence[IDX(x, y)] + p[IDX(x-1, y)] + p[IDX(x+1, y)] + p[IDX(x, y-1)] + p[IDX(x, y+1)])/4;
			}
		}
	}

	// TODO:
	float rho = 1;
	float scaleX = 1.0f / (rho * hX);
	float scaleY = 1.0f / (rho * hY);
	for(size_t y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] != FLUID) continue;
			u[IDX(x  , y)] -= scaleX * p[IDX(x, y)];
			u[IDX(x+1, y)] += scaleX * p[IDX(x, y)];

			v[IDX(x, y  )] -= scaleY * p[IDX(x, y)];
			v[IDX(x, y+1)] += scaleY * p[IDX(x, y)];
		}
	}

	float maxDiv = 0, sumDiv = 0;
	int numCells = 0;
	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] == FLUID)
			{
				float cellDiv		 =	-(hX * (u[IDX(x+1, y)] - u[IDX(x, y)]) +
										  hY * (v[IDX(x, y+1)] - v[IDX(x, y)]));
				maxDiv = (std::max)(maxDiv, fabsf(cellDiv));
				sumDiv += fabsf(cellDiv);

				numCells++;
			}
		}
	}
	float avgDiv = sumDiv / numCells;
}

void setOuterSolidRegion()
{
	// vel x
	for(int y = 0; y < GRID_SIZE_Y ; y++)
	{
		velX[IDX(0,y)] = 0;
		velX[IDX(1,y)] = 0;
		velX[IDX(GRID_SIZE_X-1,y)] = 0;
		velX[IDX(GRID_SIZE_X,y)] = 0;
	}
	for(int x = 1; x < GRID_SIZE_X ; x++)
	{
		velX[IDX(x,0)] = velX[IDX(x,1)];
		velX[IDX(x,GRID_SIZE_Y-1)] = velX[IDX(x,GRID_SIZE_Y-2)];
	}

	// vel y
	for(int x = 0; x < GRID_SIZE_X ; x++)
	{
		velY[IDX(x,0)] = 0;
		velY[IDX(x,1)] = 0;
		velY[IDX(x,GRID_SIZE_Y-1)] = 0;
		velY[IDX(x,GRID_SIZE_Y)] = 0;
	}
	for(int y = 1; y < GRID_SIZE_Y ; y++)
	{
		velY[IDX(0,y)] = velY[IDX(1,y)];
		velY[IDX(GRID_SIZE_X-1,y)] = velY[IDX(GRID_SIZE_X-2,y)];
	}
	

	for(int y = 0; y < GRID_SIZE_Y; y++)
	{
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			if(x == 0 || y == 0 || x == GRID_SIZE_X-1 || y == GRID_SIZE_Y-1)
			{
				cellType[IDX(x,y)] = SOLID;
				pressure[IDX(x,y)] = 0;
			}
			else
				cellType[IDX(x,y)] = FLUID;
		}
	}
}

static void resetSources()
{
	for(int y = 0; y < GRID_SIZE_Y; y++)
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			velXSources[IDX(x,y)] = 0;
			velYSources[IDX(x,y)] = 0;
			densitySources[IDX(x,y)] = 0;
		}
}

static void addVelocitySources()
{
	for(int y = 0; y < GRID_SIZE_Y; y++)
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] != FLUID) continue;
			velX[IDX(x,y)] += velXSources[IDX(x,y)] * 0.5f;
			velX[IDX(x+1,y)] += velXSources[IDX(x,y)] * 0.5f;
			velY[IDX(x,y)] += velYSources[IDX(x,y)] * 0.5f;
			velY[IDX(x,y+1)] += velYSources[IDX(x,y)] * 0.5f;
		}
}

static void addDensitySources()
{
	for(int y = 0; y < GRID_SIZE_Y; y++)
		for(int x = 0; x < GRID_SIZE_X; x++)
		{
			if(cellType[IDX(x,y)] != FLUID) continue;
			density[IDX(x,y)] += densitySources[IDX(x,y)];
		}
}

void WaterView::update( float dt )
{
	setOuterSolidRegion();
	std::swap(velX, velXPrev);
	std::swap(velY, velYPrev);
	advectVelX(velX, velXPrev, velXPrev, velYPrev, dt);
	advectVelY(velY, velYPrev, velXPrev, velYPrev, dt);
	addVelocitySources();
	//setOuterSolidRegion();
	project(velX, velY, pressure, divergence);
	//projectPcg(velX, velY, pressure, divergence, dt);

	setOuterSolidRegion();

	addDensitySources();
	std::swap(density, densityPrev);
	advectCellValue(density, densityPrev, velX, velY, dt);

	resetSources();
}


static void reset()
{
	for(uint y = 0; y < GRID_SIZE_Y; y++)
	{
		for(uint x = 0; x < GRID_SIZE_X; x++)
		{

			velX[IDX(x,y)] = 0;
			velX[IDX(x+1,y)] = 0;
			velY[IDX(x,y)] = 0;
			velY[IDX(x,y+1)] = 0;

			velXPrev[IDX(x,y)] = 0;
			velXPrev[IDX(x+1,y)] = 0;
			velYPrev[IDX(x,y)] = 0;
			velYPrev[IDX(x,y+1)] = 0;

			density[IDX(x,y)] = 0;
			densityPrev[IDX(x,y)] = 0;

		}
	}
}

static void initGui()
{

}
void WaterView::init()
{
	srand(time(NULL));

	View::load();

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;
	mFluidDensityTex = rdr->addTexture2D(NULL, GRID_SIZE_X, GRID_SIZE_Y, DXGI_FORMAT_R32_FLOAT, true);

	velX = velocityXBuffer0;
	velY = velocityYBuffer0;
	velXPrev = velocityXBuffer1;
	velYPrev = velocityYBuffer1;

	density = densityBuffer0;
	densityPrev = densityBuffer1;

	reset();
	
	mArrowTex = mgfx::loadTextureFromFile("arrow.bmp");
	mShaderSprite = mgfx::loadShaderFromFile("Font.fx");
	mShaderFluid = mgfx::loadShaderFromFile("SimpleTextured2D.fx");
	createSpriteBuffers();

	resetSources();

	mDrawVelocity = true;

	initGui();
}

void WaterView::unload()
{

	View::unload();
}

static void updateTextures()
{
	uint rowPitch;
	byte * mem = mgfx::Renderer::Instance->mapTexture(mFluidDensityTex, &rowPitch, NULL);

	for( size_t row = 0; row < GRID_SIZE_X; row++ )
	{
		size_t rowStart = row * rowPitch;
		for( size_t col = 0; col < GRID_SIZE_Y; col++ )
		{
			if(cellType[IDX(col,row)] == SOLID)
				*((float*)&mem[rowStart + col * 4]) = 1.0f;
			else
				*((float*)&mem[rowStart + col * 4]) = density[IDX(col, row)];
		}
	}

	mgfx::Renderer::Instance->unmapTexture(mFluidDensityTex);
}

static void createSpriteBuffers()
{
	// vertex buffer
	mgfx::VertexPositionTexture vertices[4];

	vertices[0].Position = XMFLOAT3(0.0f, -0.5f, 0.5f);
	vertices[1].Position = XMFLOAT3(0.0f,  0.5f, 0.5f);
	vertices[2].Position = XMFLOAT3(1.0f, -0.5f, 0.5f);
	vertices[3].Position = XMFLOAT3(1.0f,  0.5f, 0.5f);

	vertices[0].TextureCoord = XMFLOAT2(0, 0);
	vertices[1].TextureCoord = XMFLOAT2(0, 1);
	vertices[2].TextureCoord = XMFLOAT2(1, 0);
	vertices[3].TextureCoord = XMFLOAT2(1, 1);

	mSpriteVertexBuffer = mgfx::Renderer::Instance->addVertexBuffer(&vertices[0], 4, sizeof(mgfx::VertexPositionTexture));

	// index buffer
	short indices[6];

	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;

	indices[3] = 1;
	indices[4] = 3;
	indices[5] = 2;

	mSpriteIndexBuffer = mgfx::Renderer::Instance->addIndexBuffer(indices, 6, sizeof(short));
}

static void drawVelocity()
{
	uint scrWid = mcore::GlobalAppData::Instance.ScreenWidth;
	uint scrHei = mcore::GlobalAppData::Instance.ScreenHeight;

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;

	rdr->setVertexFormat(mgfx::VertexPositionTexture::VertexFormat);
	rdr->setVertexBuffer(mSpriteVertexBuffer);
	rdr->setIndexBuffer(mSpriteIndexBuffer);
	rdr->setPrimitiveType(mgfx::TRIANGLE_LIST);

	rdr->setShader(mShaderSprite);
	rdr->setShaderResource("gTexture", mArrowTex);

	for(size_t y = 0; y < GRID_SIZE_Y; y+=4)
	{
		for(size_t x = 0; x < GRID_SIZE_X; x+=4)
		{
			float u = 0.5f * (velX[IDX(x,y)] + velX[IDX(x+1,y)]);
			float v = 0.5f * (velY[IDX(x,y)] + velY[IDX(x,y+1)]);
			float angle = atan2(v, u);
			float length = sqrtf(u*u + v*v);



			XMMATRIX transform = XMMatrixMultiply(
				XMMatrixMultiply(
				XMMatrixScaling(length * 0.001f, length * 0.00025f, 1.0f),
				XMMatrixRotationZ(-angle)),
				XMMatrixTranslation(x / float(GRID_SIZE_X / 2) - 1.0f, -int(y) / float(GRID_SIZE_Y / 2) + 1.0f, 0.0f)
				);

			rdr->setShaderMatrix("gWorld", (float*)&transform);

			rdr->drawIndexed();

		}
	}
}

void WaterView::draw()
{
	updateTextures();

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;

	rdr->setShader(mShaderFluid);
	rdr->setShaderResource("gTexture", mFluidDensityTex);
	rdr->drawFullScreenQuad();

	rdr->setShaderResource("gTexture", NULL);
	rdr->applyConstantsWithoutDrawing();

	if(mDrawVelocity)
		drawVelocity();

	mGui->draw();
}

bool WaterView::onWindowMessage( UINT msg, WPARAM wParam, LPARAM lParam )
{
	if(sendInputToGUI(msg, wParam, lParam))
		return true;

	static bool holdingLeft = false;
	static bool holdingRight = false;
	static int prevMouseX, prevMouseY;

	switch(msg)
	{
		case WM_LBUTTONDOWN:
			holdingLeft = true;
			prevMouseX = LOWORD(lParam);
			prevMouseY = HIWORD(lParam);
			break;

		case WM_LBUTTONUP:
			holdingLeft = false;
			break;

		case WM_RBUTTONDOWN:
			holdingRight = true;
			prevMouseX = LOWORD(lParam);
			prevMouseY = HIWORD(lParam);
		break;

		case WM_RBUTTONUP:
			holdingRight = false;
			break;

		case WM_MOUSEMOVE:
			{
				if(holdingLeft || holdingRight)
				{

					float xPrev = GRID_SIZE_X * prevMouseX / (float)mcore::GlobalAppData::Instance.ScreenWidth;
					float yPrev = GRID_SIZE_Y * prevMouseY / (float)mcore::GlobalAppData::Instance.ScreenHeight;
					float xCurr = GRID_SIZE_X * LOWORD(lParam) / (float)mcore::GlobalAppData::Instance.ScreenWidth;
					float yCurr = GRID_SIZE_Y * HIWORD(lParam) / (float)mcore::GlobalAppData::Instance.ScreenHeight;

					float xS = (std::min)(xPrev, xCurr); float xL = (std::max)(xPrev, xCurr);
					float yS = (std::min)(yPrev, yCurr); float yL = (std::max)(yPrev, yCurr);
					
					for(size_t y = (size_t)yS; y <= yL; y++)
					{
						for(size_t x = (size_t)xS; x <= xL; x++)
						{
							if(holdingRight)
							{
								velXSources[IDX((size_t)x, (size_t)y)] += 300*(LOWORD(lParam) - prevMouseX);
								velYSources[IDX((size_t)x, (size_t)y)] += 300*(HIWORD(lParam) - prevMouseY);
							}
							if(holdingLeft)
							{
								densitySources[IDX((size_t)x, (size_t)y)] += 1.0f;
							}
						}
					}

					prevMouseX = LOWORD(lParam);
					prevMouseY = HIWORD(lParam);
				}
			}
			break;
	}
	return false;
}
